package model;

import java.util.List;
import java.util.Random;
import tool.Randomizer;

/**
 * A class representing shared characteristics of animals.
 * 
 * @author Team X
 * @version 1
 */
public abstract class Animal implements Actor
{
    // Whether the animal is alive or not.
    private boolean alive;
    // The animal's field.
    protected Field field;
    // The animal's position in the field.
    protected Location location;
    // The animal's age.
    protected int age;
    // The animal's food level.
    protected int food;
    // The animal's sickness
    public boolean sick = false;    
    // A shared random number generator to control breeding.
    public static final Random rand = Randomizer.getRandom();
    
    /**
     * Create a new animal at location in field.
     * 
     * @param field The field currently occupied.
     * @param location The location within the field.
     */
    public Animal(boolean randomAge,Field field, Location location)
    {
        alive = true;
        this.field = field;
        setLocation(location);
        reset();
        
        // Set age
        if(randomAge) age = rand.nextInt(getMaxAge());
        else age = 0;
    }
    
    /**
     * Make this animal act - that is: make it do
     * whatever it wants/needs to do.
     * @param newAnimals A list to add newly born animals to.
     */
    public abstract void act(List<Animal> newAnimals);

    /**
     * Check whether the animal is alive or not.
     * @return true if the animal is still alive.
     */
    public boolean isAlive()
    {
        return alive;
    }

    /**
     * Indicate that the animal is no longer alive.
     * It is removed from the field.
     */
    public void setDead()
    {
        alive = false;
        if(location != null) {
            field.clear(location);
            location = null;
            field = null;
        }
    }

    /**
     * Return the animal's location.
     * @return The animal's location.
     */
    public Location getLocation()
    {
        return location;
    }
    
    /**
     * Return the animal's field.
     * @return The animal's field.
     */
    public Field getField()
    {
        return field;
    }
    
    /**
     * Place the animal at the new location in the given field.
     * @param newLocation The animal's new location.
     */
    public void setLocation(Location newLocation)
    {
        if(location != null) {
            field.clear(location);
        }
        location = newLocation;
        field.place(this, newLocation);
    }
    
    /**
     * Sickness
     */
    public void becomeSick()
    {
    	// 0.01 % chance to get sick
    	if(rand.nextDouble() < 0.01)
    	{ this.sick = true; }
    }
    
    /**
     * Increase the age.
     * This could result in the animals death.
     */
    protected void incrementAge()
    {
        age++;
        if(age > getMaxAge()) 
        setDead();
    }

    /**
     * Increment animal's hunger
     */
    protected void incrementHunger()
    {
    	if(!sick) food--;
    	else food -= 3;
    		
    	if(food <= -5) 
    	setDead();
    }
    
    /**
     * Generate a number representing the number of births,
     * if it can breed.
     * @return The number of births (may be zero).
     */
    protected int breed()
    {
        int births = 0;
        if(canBreed() && rand.nextDouble() <= getBreedingprobability()) 
        {
            births = rand.nextInt(getMaxLitterSize()) + 1;
        }
        return births;
    }

    /**
     * A animal can breed if it has reached the breeding age.
     * @return true if the animal can breed, false otherwise.
     */
    private boolean canBreed()
    {
        return age >= getBreedingAge();
    }
    
    public abstract int getBreedingAge();
    public abstract int getMaxAge();
    public abstract double getBreedingprobability();
    public abstract int getMaxLitterSize();
    public abstract void reset();
    protected abstract void giveBirth(List<Animal> newAnimals);
    public abstract void setBreedingAge(int age);
    public abstract void setMaxAge(int age);
    public abstract void setBreedingprobability(double probability);
    public abstract void setMaxLitterSize(int age);
}

